import java.io.*;
import java.util.StringTokenizer;


public class Client implements Runnable{

	//Primary Server info
	public static String serverIpAddress = "localhost";	
	public static int serverPort = 3333;
	
	//Backup Server info
	public static String bsIpAddress = "";
	public static int bsPort = 0;
	
	static final String joinCmd = "startGame";
	static final String moveCmd = "move";
	static final String quitCmd = "quit";
	
	public static final String OKCode = "200";
	
	String username = "";
	boolean inGame = false;
	int collectedTreasure = 0, x = 0,y = 0;
	
	public String readCommand(){
		String msg = "";
		
		BufferedReader userInput = new BufferedReader(new InputStreamReader(System.in));
		try {
			msg = userInput.readLine();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
		return msg;
	}
	
	public void printMessage(String message){
		System.out.println("[Client] "+message);
	}
	
	public void requestGame(){		
		if (!ClientConnection.openConnection(serverIpAddress,serverPort))
		{
			printMessage("Cannot connect to Server!");
			return;
		}		
		
		if (!ClientConnection.send(joinCmd))
		{
			printMessage("Cannot send Join-Game request to the Server!");
		}	
	}
	
	public String move(String direction){
		if (!ClientConnection.openConnection(serverIpAddress,serverPort))
			printMessage("Cannot connect to Server!");
		
		String moveMsg = moveCmd+"_"+username+"_"+direction.substring(4);
		
		if (!ClientConnection.send(moveMsg))
			printMessage("Cannot send Move request to the Server!");
		
		//waiting for the reply from server
		String reply = ClientConnection.receive();
		
		if (!ClientConnection.openConnection(bsIpAddress,bsPort))
			printMessage("Cannot connect to Server!");
		
		moveMsg = moveCmd+"_"+username+"_"+direction.substring(4);
		
		if (!ClientConnection.send(moveMsg))
			printMessage("Cannot send Move request to the Server!");
		
		//ClientConnection.receive();
		
		return reply;
	}
	
	/*public String moveBS(String direction){
		if (!ClientConnection.openConnection(bsIpAddress,bsPort))
			printMessage("Cannot connect to Server!");
		
		String moveMsg = moveCmd+"_"+username+"_"+direction.substring(4);
		
		if (!ClientConnection.send(moveMsg))
			printMessage("Cannot send Move request to the Server!");
			
		//waiting for the reply from server
		String reply = ClientConnection.receive();
		
		return reply;
	}*/

	public String quit(){
		if (!ClientConnection.openConnection(serverIpAddress,serverPort))
			printMessage("Cannot connect to Server!");
		
		String quitMsg = quitCmd+"_"+username;
		
		if (!ClientConnection.send(quitMsg))
			printMessage("Cannot send Quit request to the Server!");
		
		//waiting for the reply from server
		String reply = ClientConnection.receive();
		
		if (!ClientConnection.openConnection(bsIpAddress,bsPort))
			printMessage("Cannot connect to Server!");
		
		if (!ClientConnection.send(quitMsg))
			printMessage("Cannot send Quit request to the Server!");
	
		return reply;
	}
	
	public void run()
	{
		printMessage("Welcome to the Maze Game!\n");
		try 
		{
		printMessage("Please enter the Server IP: ");
		serverIpAddress = readCommand();
		printMessage("Please enter the Server port No: ");
		serverPort = Integer.parseInt(readCommand()) ;
		printMessage("To join a game type 'join'\nTo exit a game type 'quit'");
		printMessage("To move around type 'Move' + direction of N,S,W,E,NM");
		String command = "";
		do {
			System.out.print(">");
			command = readCommand();
			if (command != null) //null handler
			{
				if (command.equalsIgnoreCase("Join"))
				{
					requestGame();
					startServer();
					//startListening();
					//client now waits for the reply from Server
					System.out.println("Please wait");
					String reply = ClientConnection.receive();
					
					/**
					 * Note: Step 3: Received Message have BS's info - must capture it
					 * and store in the global parameter accordingly
					 */
					/*if (reply != null && reply.startsWith("300")) //BackupServer
					{
						//Maze game = ClientConnection.receiveGame();
						//ArrayList<Player> pList = ClientConnection.receivePlayer();
						//Server server = new Server(pList,game);
						//Server server = new Server(false,3,10);
						Server server = ClientConnection.receiveServer();
						server.start();
						reply = ClientConnection.receive(); //listen again
					}*/
					if (reply != null && reply.startsWith("200"))
					{
						StringTokenizer st = new StringTokenizer(reply,"_");
						
						//ok code
						if (st.hasMoreElements())
							st.nextElement();
						
						//userID
						if (st.hasMoreElements())
							username = st.nextToken();
						//System.out.println(username);
						//x-pos
						if (st.hasMoreElements())
							x = Integer.parseInt(st.nextToken());
						
						//y-pos
						if (st.hasMoreElements())
							y = Integer.parseInt(st.nextToken());
						
						//collected treasures
						if (st.hasMoreElements())
							collectedTreasure = Integer.parseInt(st.nextToken());
						
						//BS IP
						if (st.hasMoreElements())
							bsIpAddress = st.nextToken();
						
						//BS Port
						if (st.hasMoreElements())
							bsPort = Integer.parseInt(st.nextToken());
						
											
						printMessage("You have collected : "+collectedTreasure+" treasures");
						printMessage("Your position ("+x+","+y+")\n");
						
						//game state
						while (st.hasMoreElements())
						{
							printMessage(st.nextToken());	
							//System.out.println("game state = "+st.nextToken());
						}
					}
					else
						printMessage(reply);
					
				}
				else if ((command.equalsIgnoreCase("MoveN")) || (command.equalsIgnoreCase("MoveW")) || (command.equalsIgnoreCase("MoveE"))
						|| (command.equalsIgnoreCase("MoveS")) || (command.equalsIgnoreCase("MoveNM")))
				{
					/**
					 * Note: Step 5
					 * Client should send info to both BS and PS
					 */
					//System.out.println("BS BS BS "+bsIpAddress+" "+bsPort);
					String status = move(command); //send move command to BS and PS
					
					if (status != null && status.startsWith(OKCode))
					{
						StringTokenizer st = new StringTokenizer(status,"_");
						
						//ok code
						if (st.hasMoreElements())
							st.nextElement();
						
						//userID
						if (st.hasMoreElements())
						{
							if (!username.equalsIgnoreCase(st.nextToken()))
								printMessage("Wrong username!!!");
						}
						
						//x-pos
						if (st.hasMoreElements())
							x = Integer.parseInt(st.nextToken());
						
						//y-pos
						if (st.hasMoreElements())
							y = Integer.parseInt(st.nextToken());
						
						//collected treasures
						if (st.hasMoreElements())
							collectedTreasure = Integer.parseInt(st.nextToken());
						
											
						printMessage("You have collected : "+collectedTreasure+" treasures");
						printMessage("Your position ("+x+","+y+")\n");
						
						//game state
						while (st.hasMoreElements())
							printMessage(st.nextToken());	
					}
					else
					{
						printMessage(status);
					}
				}
				else if (command.equalsIgnoreCase("Quit"))
				{
					/**
					 * Note: Step 5
					 * Client should send info to both BS and PS
					 */
					String reply = quit();
					if (reply != null && reply.startsWith(OKCode))
					{
						StringTokenizer st = new StringTokenizer(reply,"_");
						
						//ok code
						if (st.hasMoreElements())
							st.nextElement();
						
						while (st.hasMoreElements())
							printMessage(st.nextToken());					
					}					
				}
				else
				{
					printMessage("Invalid input!");
				}
			}
		}
		while (!command.equalsIgnoreCase("Quit"));
		
		ClientConnection.closeConnection();
		}
		catch (Exception e)
		{
			System.out.println("Invalid input! Please try again.");
            e.printStackTrace();
		}
	}
	
	public void startListening()
	{
		Runnable r = new Runnable() {
			  public void run(){
			    try {
			    	Server server = ClientConnection.receiveServer();
			    	server.port = server.BSPort;
			    	server.isPrimaryServer = false;
			    	server.start();
				} catch (Exception e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			  }
			};
		Thread T = new Thread(r);
		T.start();
	}
	
	public void startServer()
	{
		//When the client start the server for listening for incoming message
		//it can just initialize a default game with length of 3 and 3 treasures
		//System.out.println(""+(ClientConnection.connectionSocket.getLocalPort()+1));
		Server server = new Server(false,3,3,ClientConnection.connectionSocket.getLocalPort()+1);
		server.start();
	}
	
	public static void main(String[] args) throws Exception
	{
		//Server server = new Server(false,3,10);
		//server.start();
		Client client = new Client();
		client.run();
	}
}
